package com.guoheng.hazard.sys.service.impl.hazard;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.guoheng.hazard.common.base.Result;
import com.guoheng.hazard.common.enums.ErrorCodeEnum;
import com.guoheng.hazard.config.InfluxDBConfig;
import com.guoheng.hazard.manager.hikvision.CameraManager;
import com.guoheng.hazard.manager.websocket.WebSocketServer;
import com.guoheng.hazard.sys.mapper.entpr.*;
import com.guoheng.hazard.sys.mapper.hazard.*;
import com.guoheng.hazard.sys.model.dto.hazard.*;
import com.guoheng.hazard.sys.model.entity.entpr.*;
import com.guoheng.hazard.sys.model.entity.hazard.*;
import com.guoheng.hazard.sys.service.hazard.MonitorSensorService;
import com.guoheng.hazard.sys.service.hazard.SafeOneMapService;
import lombok.Data;
import org.influxdb.InfluxDB;
import org.springframework.beans.BeanUtils;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.guoheng.hazard.common.enums.PartTypeEnum.PART_TYPE_ONE;
import static com.guoheng.hazard.common.enums.PartTypeEnum.PART_TYPE_TWO;
import static com.guoheng.hazard.common.enums.SafeOneMapTypeEnum.*;
import static com.guoheng.hazard.common.enums.SensorTypeEnum.*;
import static com.guoheng.hazard.common.enums.WebSocketEnum.*;

/**
 * 类功能描述:　SafeOneMapServiceImpl
 *
 * @author fbl
 * @date 2019-12-02 08:39
 */
@Service
@Data
@EnableScheduling
public class SafeOneMapServiceImpl implements SafeOneMapService {

    @Resource
    MonitorSensorMapper monitorSensorMapper;

    @Resource
    SensorDataMapper sensorDataMapper;

    @Resource
    MajorHazardAlarmMapper majorHazardAlarmMapper;

    @Resource
    MonitorCameraMapper monitorCameraMapper;

    @Resource
    MajorHazardInfoMapper majorHazardInfoMapper;

    @Resource
    EntprBasicInfoMapper entprBasicInfoMapper;

    @Resource
    WebSocketServer webSocketServer;

    @Resource
    CameraManager cameraManager;

    @Resource
    MajorHazardUnitMapper majorHazardUnitMapper;

    @Resource
    StorageTankMapper storageTankMapper;

    @Resource
    StorageRoomMapper storageRoomMapper;

    @Resource
    ProductionPlaceMapper productionPlaceMapper;

    @Resource
    MajorHazardMaterialMapper majorHazardMaterialMapper;

    @Resource
    InfluxDB influxDB;

    @Resource
    InfluxDBConfig influxDBConfig;

    @Resource
    MonitorSensorServiceImpl monitorSensorServiceImpl;

    @Override
    public Result getSafeOneMap(GetSafeOneMapDTO getSafeOneMapDTO) {
        // 企业id
        Long entprId = getSafeOneMapDTO.getEntprId();
        // 类型参数选择
        List<Integer> types = getSafeOneMapDTO.getTypes();

        HashMap<String, Object> oneMapResult = new HashMap<>();
        for (Integer type : types) {
            if (type.equals(ONE_MAP_TYPE_ZERO.getCode())) {
                // 重大危险源
                ArrayList<MajorHazardInfoSelectDTO> majorHazardInfoSelectDTOS = new ArrayList<>();
                List<MajorHazardInfo> hazardInfo = majorHazardInfoMapper.getHazardInfo(null, entprId);
                for (MajorHazardInfo majorHazardInfo : hazardInfo) {
                    MajorHazardInfoSelectDTO majorHazardInfoSelectDTO = new MajorHazardInfoSelectDTO();
                    BeanUtils.copyProperties(majorHazardInfo, majorHazardInfoSelectDTO);
                    String majorScope = majorHazardInfo.getMajorScope();
                    JSONArray majorScopeJson = JSONArray.parseArray(majorScope);
                    majorHazardInfoSelectDTO.setMajorScope(majorScopeJson);
                    // 得到企业名称
                    Long eId = majorHazardInfo.getEntprId();
                    EntprBasicInfo entprBasicInfoById = entprBasicInfoMapper.getEntprBasicInfoById(eId);
                    majorHazardInfoSelectDTO.setEntprName(entprBasicInfoById.getEntprName());
                    majorHazardInfoSelectDTOS.add(majorHazardInfoSelectDTO);
                }
                oneMapResult.put("majorHazardInfo", majorHazardInfoSelectDTOS);
            }

            // 温度传感器
            if (type.equals(ONE_MAP_TYPE_TWO.getCode())) {
                setSensorData(entprId, 1, oneMapResult);
            }
            // 压力传感器
            if (type.equals(ONE_MAP_TYPE_THREE.getCode())) {
                setSensorData(entprId, 2, oneMapResult);
            }
            // 液位传感器
            if (type.equals(ONE_MAP_TYPE_FOUR.getCode())) {
                setSensorData(entprId, 3, oneMapResult);
            }
            // 可燃传感器
            if (type.equals(ONE_MAP_TYPE_FIVE.getCode())) {
                setSensorData(entprId, 5, oneMapResult);
            }
            // 有毒传感器
            if (type.equals(ONE_MAP_TYPE_SIX.getCode())) {
                setSensorData(entprId, 4, oneMapResult);
            }
            // 摄像头
            if (type.equals(ONE_MAP_TYPE_SEVEN.getCode())) {
                // 查询该企业下的摄像头
                List<MonitorCameraPageDTO> monitorCameras = monitorCameraMapper.getMonitorCameras(entprId, null, null);
                ArrayList<OneMapLocationDTO> oneMapLocationDTOS = new ArrayList<>();
                for (MonitorCameraPageDTO monitorCamera : monitorCameras) {
                    OneMapLocationDTO oneMapLocationDTO = new OneMapLocationDTO();
                    BeanUtils.copyProperties(monitorCamera, oneMapLocationDTO);
                    oneMapLocationDTOS.add(oneMapLocationDTO);
                }
                oneMapResult.put("camera", oneMapLocationDTOS);
            }
        }
        return Result.success(oneMapResult);
    }

    @Override
    public Result realTimeCamera(Long id) {
        // 查询摄像头信息
        MonitorCamera monitorCamera = monitorCameraMapper.selectByPrimaryKey(id);
        // 查询摄像头关联的indexCode
        String indexCode = monitorCameraMapper.getIndexCode(monitorCamera.getId());
        try {
          /*  String previewURLs = cameraManager.getPreviewURLs(indexCode);
            JSONObject jsonObject = JSON.parseObject(previewURLs);
            String data = jsonObject.getString("data");
            JSONObject dataJsonObject = JSON.parseObject(data);
            String url = dataJsonObject.getString("url");*/
            HashMap<String, Object> result = new HashMap<>();
            result.put("url", "https://cdn.letv-cdn.com/2018/12/05/JOCeEEUuoteFrjCg/playlist.m3u8");
            result.put("cameraName", monitorCamera.getCameraName());
            return Result.success(result);
        } catch (Exception e) {
            return Result.success(ErrorCodeEnum.SYS_ERR_CONNECTION_TIME_OUT);
        }
    }

    @Override
    public Result majorHazard(Long id) {
        // 重大危险源基本信息
        MajorHazardInfo majorHazardInfo = majorHazardInfoMapper.selectByPrimaryKey(id);
        MajorHazardInfoSelectDTO majorHazardInfoSelectDTO = new MajorHazardInfoSelectDTO();
        BeanUtils.copyProperties(majorHazardInfo, majorHazardInfoSelectDTO);
        String majorScope = majorHazardInfo.getMajorScope();
        JSONArray majorScopeJson = JSONArray.parseArray(majorScope);
        majorHazardInfoSelectDTO.setMajorScope(majorScopeJson);
        // 置入企业名称
        Long entprId = majorHazardInfo.getEntprId();
        EntprBasicInfo entprBasicInfoById = entprBasicInfoMapper.getEntprBasicInfoById(entprId);
        majorHazardInfoSelectDTO.setEntprName(entprBasicInfoById.getEntprName());
        // 查看重大危险源涉及到哪些单元
        List<MajorHazardUnit> majorHazardUnitByMajorId = majorHazardUnitMapper.getMajorHazardUnitByMajorId(id);
        // 置入介质信息
        ArrayList<MajorHazardMaterialDTO> majorHazardMaterialDTOS = new ArrayList<>();
        // 置入单元信息
        ArrayList<MajorHazardUnitDTO> majorHazardUnitDTOS = new ArrayList<>();
        // 置入介质信息
        ArrayList<MajorHazardSenSorDTO> majorHazardSenSorDTOS = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(majorHazardUnitByMajorId)) {
            for (MajorHazardUnit majorHazardUnit : majorHazardUnitByMajorId) {
                MajorHazardUnitDTO majorHazardUnitDTO = new MajorHazardUnitDTO();
                // 查询组成部分详情
                Integer partType = majorHazardUnit.getPartType();
                Long partId = majorHazardUnit.getPartId();
                majorHazardUnitDTO.setId(majorHazardUnit.getId());
                // 储罐
                if (partType.equals(PART_TYPE_ONE.getCode())) {
                    // 储罐详情
                    StorageTank entprTankById = storageTankMapper.getEntprTankById(partId);
                    // 投用时间
                    majorHazardUnitDTO.setProductionDate(entprTankById.getProductionDate());
                    // 在厂区的位置
                    majorHazardUnitDTO.setLocFactory(entprTankById.getLocFactory());
                    // 储罐名称
                    majorHazardUnitDTO.setPartName(entprTankById.getTankName());
                } else if (partType.equals(PART_TYPE_TWO.getCode())) {
                    // 库房详情
                    StorageRoom storageRoom = storageRoomMapper.selectByPrimaryKey(partId);
                    // 投用时间
                    majorHazardUnitDTO.setProductionDate(storageRoom.getProductionDate());
                    // 在厂区的位置
                    majorHazardUnitDTO.setLocFactory(storageRoom.getLocFactory());
                    // 库房名称
                    majorHazardUnitDTO.setPartName(storageRoom.getRoomName());
                } else {
                    // 生产场所详情
                    ProductionPlace placeById = productionPlaceMapper.getPlaceById(partId);
                    // 投用时间
                    majorHazardUnitDTO.setProductionDate(placeById.getProductionDate());
                    // 在厂区的位置
                    majorHazardUnitDTO.setLocFactory(placeById.getLocFactory());
                    // 场所名称
                    majorHazardUnitDTO.setPartName(placeById.getPlaceName());
                }
                // id
                majorHazardUnitDTO.setPartId(partId);
                // 单元类型
                majorHazardUnitDTO.setPartType(partType);
                // 单元编号
                majorHazardUnitDTO.setPartNo(majorHazardUnit.getPartNo());

                majorHazardUnitDTOS.add(majorHazardUnitDTO);

                // 查询各个组成部分中的介质
                MajorHazardMaterialDTO majorHazardMaterialDTO = new MajorHazardMaterialDTO();
                List<MajorHazardMaterial> majorMaterial = majorHazardMaterialMapper.getMajorMaterial(partType, partId);
                if (CollectionUtil.isNotEmpty(majorMaterial)) {
                    for (MajorHazardMaterial majorHazardMaterial : majorMaterial) {
                        BeanUtils.copyProperties(majorHazardMaterial, majorHazardMaterialDTO);
                    }
                    majorHazardMaterialDTOS.add(majorHazardMaterialDTO);
                }
            }
        }

        // 查询重大危险源的传感器信息
        List<MonitorSensor> sensorByHazardId = monitorSensorMapper.getSensorByHazardId(id);

        if (CollectionUtil.isNotEmpty(sensorByHazardId)) {
            for (MonitorSensor monitorSensor : sensorByHazardId) {
                MajorHazardSenSorDTO majorHazardSenSorDTO = new MajorHazardSenSorDTO();
                BeanUtils.copyProperties(monitorSensor, majorHazardSenSorDTO);
                majorHazardSenSorDTOS.add(majorHazardSenSorDTO);
            }
        }
        // 置入重大危险源传感器信息
        majorHazardInfoSelectDTO.setMajorHazardSenSores(majorHazardSenSorDTOS);
        // 重大危险源所涉及的单元列表
        majorHazardInfoSelectDTO.setMajorHazardUnits(majorHazardUnitDTOS);
        // 重大危险源所涉及的介质列表
        majorHazardInfoSelectDTO.setMajorHazardMaterials(majorHazardMaterialDTOS);

        // 查询重大危险源摄像头信息
        ArrayList<MajorHazardCameraDTO> majorHazardCameraDTOS = new ArrayList<>();
        List<MonitorCamera> monitorCamerasByHazardId = monitorCameraMapper.getMonitorCamerasByHazardId(id);
        if (CollectionUtil.isNotEmpty(monitorCamerasByHazardId)) {
            for (MonitorCamera monitorCamera : monitorCamerasByHazardId) {
                MajorHazardCameraDTO majorHazardCameraDTO = new MajorHazardCameraDTO();
                BeanUtils.copyProperties(monitorCamera, majorHazardCameraDTO);
                majorHazardCameraDTOS.add(majorHazardCameraDTO);
            }
        }
        // 置入重大危险源摄像头信息
        majorHazardInfoSelectDTO.setMajorHazardCameras(majorHazardCameraDTOS);
        return Result.success(majorHazardInfoSelectDTO);
    }

    @Override
    public Result searchSensorRecord(Long id, Long beginTime, Long endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 查询传感器列表
        String begin = "";
        String end = "";
        if (beginTime != null) {
            Date date = new Date(beginTime);
            begin = sdf2.format(date);
        } else {
            // 默认查当天
            Date date = new Date();
            begin = sdf.format(date) + " 00:00:00";
        }
        if (endTime != null) {
            Date date = new Date(endTime);
            end = sdf2.format(date);
        } else {
            // 默认查当天
            Date date = new Date();
            end = sdf.format(date) + " 23:59:59";
        }

        String sql = "select sensorValue,time from " + influxDBConfig.getMeasurement() + " where time < " + "'" + end + "' and time >" + "'" + begin + "'";
        if (id != null) {
            sql += "and sensorId = " + "'" + id + "'";
        }
        // influxDB时区
        sql += "order by time desc tz('Asia/Shanghai')";

        List<Map> query = monitorSensorServiceImpl.query(influxDB, sql, Map.class);
        for (Map map : query) {
            String time = map.get("time").toString();
            BigDecimal bd = new BigDecimal(time);
            map.put("time",bd.toPlainString());
        }

        return Result.success(query);
    }

    @Override
    public Result safeOneMapDataNum(Long entprId) {
        SafeOneMapDataNumDTO safeOneMapDataNumDTO = new SafeOneMapDataNumDTO();
        safeOneMapDataNumDTO.setEntprId(entprId);
        // 企业详情安全一张图中的数量信息
        // 重大危险源数量
        List<MajorHazardInfo> hazardInfo = majorHazardInfoMapper.getHazardInfo(null, entprId);
        safeOneMapDataNumDTO.setMajor(hazardInfo.size());
        // 实时报警
        List<MajorHazardAlarmSelectDTO> alarm = majorHazardAlarmMapper.getAlarm(entprId, null, null
                , null, null, 1);
        safeOneMapDataNumDTO.setAlarm(alarm.size());
        // 各种数据传感器
        Integer temp = totalSensor(entprId, SENSOR_TYPE_ONE.getCode());
        safeOneMapDataNumDTO.setTemp(temp);
        Integer pressure = totalSensor(entprId, SENSOR_TYPE_TWO.getCode());
        safeOneMapDataNumDTO.setPressure(pressure);
        Integer liquid = totalSensor(entprId, SENSOR_TYPE_THREE.getCode());
        safeOneMapDataNumDTO.setLiquid(liquid);
        Integer combustible = totalSensor(entprId, SENSOR_TYPE_FIVE.getCode());
        safeOneMapDataNumDTO.setCombustible(combustible);
        Integer poisonous = totalSensor(entprId, SENSOR_TYPE_FOUR.getCode());
        safeOneMapDataNumDTO.setPoisonous(poisonous);
        // 摄像头
        List<MonitorCameraPageDTO> monitorCameras = monitorCameraMapper.getMonitorCameras(entprId, null, null);
        safeOneMapDataNumDTO.setCamera(monitorCameras.size());
        // 报警
        safeOneMapDataNumDTO.setMajorHazardAlarmSelectDTOS(alarm);
        return Result.success(safeOneMapDataNumDTO);
    }

    @Override
    public Result sensorData(Long sensorId) {

        // 查询传感器数据(influxDB数据库中最新数据)
        String sql = "select sensorId,sensorValue,time from " + influxDBConfig.getMeasurement();
        if (sensorId != null) {
            sql += " where sensorId = " + "'" + sensorId + "'";
        }
        sql += "order by time desc limit 1";
        List<Map> query = monitorSensorServiceImpl.query(influxDB, sql, Map.class);
        SensorDataRealTimeDTO sensorDataRealTime = monitorSensorMapper.getSensorDataRealTime(sensorId);
        if(CollectionUtil.isNotEmpty(query)){
            sensorDataRealTime.setCurrentValue(Double.valueOf(query.get(0).get("sensorValue").toString()));
            String time = query.get(0).get("time").toString();
            BigDecimal bd = new BigDecimal(time);
            sensorDataRealTime.setReportTime(new Date(Long.valueOf(bd.toPlainString())));
        }
        if (sensorDataRealTime != null) {
            Integer status = sensorAlarm(sensorDataRealTime);
            sensorDataRealTime.setStatus(status);
        }
        return Result.success(sensorDataRealTime);

    }

    /**
     * 方法功能描述: 传感器位置信息的录入
     *
     * @param entprId    企业id
     * @param sensorType 传感器类型
     * @return ArrayList<OneMapTempDTO>
     */
    private void setSensorData(Long entprId, Integer sensorType, HashMap<String, Object> oneMapResult) {
        ArrayList<OneMapLocationDTO> oneMapLocations = new ArrayList<>();
        // 该企业下的传感器
        List<MonitorSensor> sensorByType = monitorSensorMapper.getSensorByType(entprId, null, sensorType);
        for (MonitorSensor monitorSensor : sensorByType) {
            OneMapLocationDTO oneMapLocationDTO = new OneMapLocationDTO();
            BeanUtils.copyProperties(monitorSensor, oneMapLocationDTO);
            oneMapLocations.add(oneMapLocationDTO);
        }
        if (sensorType.equals(SENSOR_TYPE_ONE.getCode())) {
            oneMapResult.put("temp", oneMapLocations);
        } else if (sensorType.equals(SENSOR_TYPE_TWO.getCode())) {
            oneMapResult.put("pressure", oneMapLocations);
        } else if (sensorType.equals(SENSOR_TYPE_FOUR.getCode())) {
            oneMapResult.put("poisonous", oneMapLocations);
        } else if (sensorType.equals(SENSOR_TYPE_FIVE.getCode())) {
            oneMapResult.put("combustible", oneMapLocations);
        } else if (sensorType.equals(SENSOR_TYPE_THREE.getCode())) {
            oneMapResult.put("liquid", oneMapLocations);
        }
    }


    private Integer totalSensor(Long entprId, Integer sensorType) {
        List<MonitorSensor> sensorByType = monitorSensorMapper.getSensorByType(entprId, null, sensorType);
        return sensorByType.size();
    }

    /**
     * 报警
     *
     * @param sensorDataRealTime  传感器数据
     * @return Integer
     */
    private Integer sensorAlarm(SensorDataRealTimeDTO sensorDataRealTime) {
        Double first = sensorDataRealTime.getFirstAlarmThreshold();
        Double second = sensorDataRealTime.getSecondAlarmThreshold();
        Double third = sensorDataRealTime.getThirdAlarmThreshold();
        Double forth = sensorDataRealTime.getFourthAlarmThreshold();
        Double currentValue = sensorDataRealTime.getCurrentValue();
        if(currentValue == null){
            return 0;
        }

        if (second != null && currentValue < second) {
            if (first != null && currentValue < first) {
                return 1;
            }
            return 1;
        }
        if (third != null && currentValue > third) {

            if (forth != null && currentValue > forth) {
                return 1;
            }
            return 1;
        }
        return 0;
    }

}